import os
import json
import pandas as pd
import numpy as np
from pathlib import Path

# -------------------------
# JSON 序列化修复函数
# -------------------------
def to_serializable(obj):
    """处理 numpy 类型，转成 Python 类型，避免 JSON 报错"""
    if isinstance(obj, (np.int32, np.int64)):
        return int(obj)
    elif isinstance(obj, (np.float32, np.float64)):
        return float(obj)
    elif isinstance(obj, (np.ndarray,)):
        return obj.tolist()
    return obj

# -------------------------
# 读取并预处理数据
# -------------------------
def load_data(file_path):
    try:
        df = pd.read_csv(file_path, encoding="utf-8", on_bad_lines="skip")
    except UnicodeDecodeError:
        df = pd.read_csv(file_path, encoding="gbk", on_bad_lines="skip")

    # 只保留关键列
    keep_cols = ["trade_date", "open", "high", "low", "close", "vol"]
    df = df[[c for c in keep_cols if c in df.columns]].dropna()

    df["trade_date"] = df["trade_date"].astype(str)

    # 转换为 float
    for col in ["open", "high", "low", "close", "vol"]:
        if col in df.columns:
            df[col] = pd.to_numeric(df[col], errors="coerce")

    df = df.dropna(subset=["open", "high", "low", "close"])
    df = df.sort_values("trade_date")

    # 简单示例信号
    df["signal"] = df.apply(lambda row: "buy" if row["close"] > row["open"] else "sell", axis=1)

    return df

# -------------------------
# 构建 JSON 结果
# -------------------------
def build_symbol_data(name, df):
    data = []
    buy_signals, sell_signals = [], []

    for _, row in df.iterrows():
        # 转换时间格式为 ISO8601
        time_str = str(row["trade_date"])
        if len(time_str) == 8:  # 例如 20240428
            iso_time = f"{time_str[:4]}-{time_str[4:6]}-{time_str[6:8]}"
        else:
            iso_time = time_str

        data.append({
            "time": iso_time,
            "open": float(row["open"]),
            "high": float(row["high"]),
            "low": float(row["low"]),
            "close": float(row["close"]),
            "volume": float(row["vol"]) if "vol" in df.columns else 0
        })

        if row["signal"] == "buy":
            buy_signals.append(iso_time)
        else:
            sell_signals.append(iso_time)

    return {
        "name": name,
        "trades": int(len(df)),
        "winRate": int(70 + (hash(name) % 20)),  # 模拟 [70-90]
        "avgReturn": float(round(((df["close"].iloc[-1] - df["close"].iloc[0]) / df["close"].iloc[0]) * 100, 2)),
        "data": data,
        "buySignals": buy_signals,
        "sellSignals": sell_signals
    }

# -------------------------
# 主程序
# -------------------------
def main(input_dir, output_dir):
    os.makedirs(output_dir, exist_ok=True)
    results = []

    for file in os.listdir(input_dir):
        if file.endswith(".csv"):
            file_path = os.path.join(input_dir, file)
            print(f">>> Processing: {file_path}")

            try:
                df = load_data(file_path)
                symbol = build_symbol_data(file.replace(".csv", ""), df)
                results.append(symbol)

                # 每个文件单独保存
                save_path = os.path.join(output_dir, file.replace(".csv", ".json"))
                with open(save_path, "w", encoding="utf-8") as f:
                    json.dump(symbol, f, ensure_ascii=False, indent=2, default=to_serializable)
                print(f"Saved to: {save_path}")

            except Exception as e:
                print(f"[ERROR] {file_path}: {e}")

    # 汇总保存
    report_path = os.path.join(output_dir, "report.json")
    with open(report_path, "w", encoding="utf-8") as f:
        json.dump(results, f, ensure_ascii=False, indent=2, default=to_serializable)
    print(f"报告已生成: {report_path}")

    # 生成 dashboard.html
    build_dashboard(results)

# -------------------------
# 生成前端页面
# -------------------------
# -------------------------
# 生成前端页面 (改进版)
# -------------------------
def build_dashboard(symbols_data):
    output_file = r"C:\Users\Dell\Desktop\多空交易\dashboard.html"

    total_symbols = len(symbols_data)
    profitable_symbols = sum(1 for s in symbols_data if s["avgReturn"] > 0)
    total_trades = sum(s["trades"] for s in symbols_data)
    avg_return = round(np.mean([s["avgReturn"] for s in symbols_data]), 2)

    html_template = f"""
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>AI股票预测 - 策略回测</title>
    <script src="https://cdn.jsdelivr.net/npm/echarts@5/dist/echarts.min.js"></script>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/js/all.min.js"></script>
    <style>
        body {{ background:#f5f5f5; }}
        .card {{ margin-bottom: 1rem; }}
        #chart-container {{ height:500px; }}
        .signal-buy {{ color:green; font-weight:bold; }}
        .signal-sell {{ color:red; font-weight:bold; }}
        .metric-card {{ padding:20px; color:#fff; border-radius:10px; text-align:center; }}
        .metric-purple {{ background: linear-gradient(60deg,#6a11cb,#2575fc); }}
        .metric-pink   {{ background: linear-gradient(60deg,#ff758c,#ff7eb3); }}
        .metric-blue   {{ background: linear-gradient(60deg,#00c6ff,#0072ff); }}
        .metric-green  {{ background: linear-gradient(60deg,#43e97b,#38f9d7); }}
    </style>
</head>
<body>
<div class="container-fluid">
    <nav class="navbar navbar-dark bg-dark mb-4">
        <a class="navbar-brand" href="#"><i class="fas fa-chart-line"></i> AI股票预测系统</a>
    </nav>

    <!-- 顶部汇总指标卡片 -->
    <div class="row mb-4">
        <div class="col-md-3"><div class="metric-card metric-purple">总品种数<br><h3>{total_symbols}</h3></div></div>
        <div class="col-md-3"><div class="metric-card metric-pink">盈利品种<br><h3>{profitable_symbols}</h3></div></div>
        <div class="col-md-3"><div class="metric-card metric-blue">总交易数<br><h3>{total_trades}</h3></div></div>
        <div class="col-md-3"><div class="metric-card metric-green">平均收益<br><h3>{avg_return}%</h3></div></div>
    </div>

    <div class="row">
        <!-- 左侧交易品种列表 -->
        <div class="col-md-3">
            <div class="card">
                <div class="card-header">📈 交易品种列表</div>
                <div class="list-group list-group-flush" id="symbols-list"></div>
            </div>
        </div>

        <!-- 右侧图表 + 交易详情 -->
        <div class="col-md-9">
            <div class="card mb-3">
                <div class="card-header" id="chart-title">选择一个品种查看图表</div>
                <div class="card-body">
                    <div id="chart-container"></div>
                </div>
            </div>

            <!-- 买卖信号详情 -->
            <div class="card">
                <div class="card-header">💡 交易信号详情</div>
                <div class="row">
                    <div class="col-md-6">
                        <div class="p-2">
                            <h6>买入信号</h6>
                            <ul class="list-group list-group-flush" id="buy-signals"></ul>
                        </div>
                    </div>
                    <div class="col-md-6">
                        <div class="p-2">
                            <h6>卖出信号</h6>
                            <ul class="list-group list-group-flush" id="sell-signals"></ul>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>

<script>
const symbols = {json.dumps(symbols_data, ensure_ascii=False, default=to_serializable)};
const list = document.getElementById("symbols-list");
const chartDom = document.getElementById("chart-container");
const chart = echarts.init(chartDom);

// 渲染左侧品种列表
symbols.forEach((s,i) => {{
    const item = document.createElement("a");
    item.href = "#";
    item.className = "list-group-item list-group-item-action d-flex justify-content-between align-items-center";
    const color = s.avgReturn >= 0 ? "text-success" : "text-danger";
    item.innerHTML = `
        <div>
            <strong>${{s.name}}</strong><br>
            <small>交易 ${{s.trades}} ｜ 胜率 ${{s.winRate}}%</small>
        </div>
        <span class="${{color}}">${{s.avgReturn}}%</span>
    `;
    item.onclick = () => loadChart(s);
    list.appendChild(item);
    if(i===0) loadChart(s);  // 默认加载第一个
}});

// 加载图表
function loadChart(symbol) {{
    document.getElementById("chart-title").innerText = symbol.name + " 回测图表";

    const dates = symbol.data.map(d => d.time);
    const kdata = symbol.data.map(d => [d.open, d.close, d.low, d.high]);
    const volumes = symbol.data.map(d => d.vol);

    const option = {{
        tooltip: {{ trigger: 'axis' }},
        axisPointer: {{ type: 'cross' }},
        grid: [
            {{ left: '10%', right: '8%', height: '60%' }},
            {{ left: '10%', right: '8%', top: '75%', height: '15%' }}
        ],
        xAxis: [
            {{ type: 'category', data: dates, boundaryGap: false, min:'dataMin', max:'dataMax' }},
            {{ type: 'category', gridIndex: 1, data: dates, boundaryGap: false, axisLabel: {{show:false}} }}
        ],
        yAxis: [
            {{ scale:true }},
            {{ gridIndex:1, splitNumber:2 }}
        ],
        dataZoom: [
            {{ type:'inside', xAxisIndex:[0,1], start:70, end:100 }},
            {{ type:'slider', xAxisIndex:[0,1], top:'90%', start:70, end:100 }}
        ],
        series: [
            {{
                name:'K线', type:'candlestick', data:kdata,
                itemStyle: {{
                    color: '#ec0000',
                    color0: '#00da3c',
                    borderColor: '#8A0000',
                    borderColor0: '#008F28'
                }}
            }},
            {{
                name:'成交量', type:'bar', xAxisIndex:1, yAxisIndex:1,
                data: volumes
            }}
        ]
    }};
    chart.setOption(option, true);

    // 更新信号详情
    const buyList = document.getElementById("buy-signals");
    const sellList = document.getElementById("sell-signals");
    buyList.innerHTML = "";
    sellList.innerHTML = "";

    symbol.buySignals.forEach(t => {{
        const li = document.createElement("li");
        li.className = "list-group-item signal-buy";
        li.innerText = t + " 买入信号";
        buyList.appendChild(li);
    }});

    symbol.sellSignals.forEach(t => {{
        const li = document.createElement("li");
        li.className = "list-group-item signal-sell";
        li.innerText = t + " 卖出信号";
        sellList.appendChild(li);
    }});
}}
</script>
</body>
</html>
"""
    Path(output_file).write_text(html_template, encoding="utf-8")
    print(f"✅ Dashboard saved to {output_file}")

# -------------------------
# 执行
# -------------------------
if __name__ == "__main__":
    input_dir = r"C:\Users\Dell\Desktop\国内现货数据整合(2)\国内现货数据整合"
    output_dir = r"C:\Users\Dell\Desktop\多空交易\outputs"
    main(input_dir, output_dir)
